﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Pavilion;

namespace Pavilion.GameTools
{
    public class EnvironmentTool : GameToolBase
    {
        public static readonly List<MultiLinePhysicalData> MultiLineDataCollection = new List<MultiLinePhysicalData>();

        public string ResourceName { get { return resourceName; } set { resourceName = value; if (resourceName != "") LoadEnvironment(resourceName); } }

        static private Dictionary<string, Action<EnvironmentTool, object>> dataExecutionDictionary;
        private List<ImageLayer> backgroundLayersList;
        private DrawVisibilityGroup drawVisibilityGroup;
        private DrawItem drawItem;
        private string resourceName;

        public EnvironmentTool(GameItem parentGameItem) : base(parentGameItem)
        {
            Initialize();
        }

        private void Initialize()
        {
            backgroundLayersList = new List<ImageLayer>();

            LoadDataExecution();
        }

        public override void Dispose()
        {
            foreach (ImageLayer imageLayer in backgroundLayersList)
                imageLayer.Dispose();

            backgroundLayersList.Clear();

            while (MultiLineDataCollection.Count != 0)
            {
                CollisionManager.Instance.RemoveMultiLineData(MultiLineDataCollection[0]);
                MultiLineDataCollection.RemoveAt(0);
            }
            drawItem.Dispose();

            base.Dispose();
        }

        private void LoadDataExecution()
        {
            if (dataExecutionDictionary != null)
                return;

            dataExecutionDictionary = new Dictionary<string, Action<EnvironmentTool, object>>();
            dataExecutionDictionary.Add("ResourceName", (environmentTool, value) => environmentTool.ResourceName = (string)value);
        }

        public override void UpdateProperty(string propertyName, object propertyValue)
        {
            dataExecutionDictionary[propertyName].Invoke(this, propertyValue);
        }

        public override void Load()
        {
            drawVisibilityGroup = ParentGameItem.DrawVisibilityGroup;

            drawItem = new DrawItem(50, () =>
            {
                foreach (MultiLinePhysicalData multiLineData in MultiLineDataCollection)
                {
                    foreach (LineVector line in multiLineData.LineCollection)
                        DrawManager.Instance.DrawLine(line.StartPosition, line.EndPosition, Color.Black);
                }
            });
            DrawManager.Instance.Add(drawItem);
            drawVisibilityGroup.Add(drawItem);
        }

        private void LoadEnvironment(string resourceName)
        {
            string directoryPath = GameEngine.GameResourcesDirectory + @"Environments\" + resourceName;

            XElement scriptNode = XDocument.Load(directoryPath + @"\script.xml").Element("script");
            IEnumerable<XElement> xmlLayerList = scriptNode.Element("LayerList").Elements("Layer");

            foreach (XElement layerNode in xmlLayerList)
                CreateImageLayer(layerNode, directoryPath + @"\Built Data");

            XElement environmentLineListNode = scriptNode.Element("EnvironmentLineList");

            if (environmentLineListNode != null)
                CreateLineSequence(environmentLineListNode.Elements("Line"));
        }

        private void CreateLineSequence(IEnumerable<XElement> lineElementCollection)
        {
            foreach (XElement lineElement in lineElementCollection)
            {
                MultiLinePhysicalData multiLineData = new MultiLinePhysicalData(this);
                multiLineData.LineType = GameEngine.ParseObject<LineType>(lineElement.Attribute("Type").Value);

                float[] points = GameEngine.ParseFloatCollection(lineElement.Attribute("Points").Value);

                for (int i = 0; i < points.Length - 2; i += 2)
                {
                    LineVector line = new LineVector();
                    line.StartPosition = new Vector2(points[i], points[i + 1]);
                    line.EndPosition = new Vector2(points[i + 2], points[i + 3]);

                    multiLineData.LineCollection.Add(line);
                }

                MultiLineDataCollection.Add(multiLineData);
                CollisionManager.Instance.AddMultiLineData(multiLineData);
            }
        }

        private void CreateImageLayer(XElement layerNode, string directoryPath)
        {
            ImageLayer imageLayer = new ImageLayer(drawVisibilityGroup);
            imageLayer.Deserialize(layerNode);
            imageLayer.Load(directoryPath);

            backgroundLayersList.Add(imageLayer);
        }
    }
}
